﻿using EmailHelper.Model;
using MailKit.Net.Smtp;
using Microsoft.Exchange.WebServices.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Task = System.Threading.Tasks.Task;

namespace EmailHelper.Exchange
{
    /// <summary>
    /// 使用托管类库去使用Exchange Webservice
    /// </summary>
    public class EWSHelper
    {
        /// <summary>
        /// ExchangeService对象
        /// </summary>
        public ExchangeService service;

        private static EWSHelper instance;
        private static readonly object syncRoot = new object();

        /// <summary>
        /// 获取EWS实例，用户名不为空则以用户名去登录
        /// </summary>
        /// <param name="eWSInitModel"></param>
        /// <param name="initAgain">是否需要重新获取实例</param>
        /// <returns></returns>
        public static EWSHelper GetInstance(EWSInitEntity eWSInitModel, bool initAgain = false)
        {
            if (instance == null || initAgain)
            {
                lock (syncRoot)
                {
                    //需要第二重判断，是因为两个线程同时过了第一重判断之后；
                    //一个等待，一个创建实例，然后等待的结束后 不能再创建实例（就通过 对象是否为null来判断）
                    if (instance == null || initAgain)
                    {
                        instance = new EWSHelper(eWSInitModel);
                    }
                }
            }
            return instance;
        }
        private EWSHelper(EWSInitEntity eWSInitModel)
        {
            //ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };//至关重要的一句 否则会报错：The Autodiscover service couldn't be located.

            //service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
            service = new ExchangeService();  //V2_8;15.00.0847.031解析出来是Exchange2013_SP1 

            if (string.IsNullOrWhiteSpace(eWSInitModel.UserName))
            {
                service.Credentials = new WebCredentials(eWSInitModel.Email, eWSInitModel.Password);
            }
            else
            {
                service.Credentials = new WebCredentials(eWSInitModel.UserName, eWSInitModel.Password, eWSInitModel.Domain);
            }
            //string userName = string.IsNullOrWhiteSpace(eWSInitModel.UserName) == true ? eWSInitModel.Email : eWSInitModel.UserName;
            //service.Credentials = new WebCredentials(userName, eWSInitModel.Password, eWSInitModel.Domain);

            var url = string.Format("https://{0}/ews/exchange.asmx", "mail.wotrus.com");
            url = string.IsNullOrWhiteSpace(eWSInitModel.EWSURL) ? url : eWSInitModel.EWSURL;
            service.Url = new Uri(url);

            service.TraceListener = new TraceListener();
            //service.TraceFlags = TraceFlags.All;
            service.TraceFlags = TraceFlags.EwsResponse | TraceFlags.EwsResponseHttpHeaders;
            service.TraceEnabled = true;
            //service.AutodiscoverUrl(_username, RedirectionUrlValidationCallback);  //这里mesince.com与wotrus.com不同，所以不用自动发现
        }
        private static bool RedirectionUrlValidationCallback(string redirectionUrl)
        {
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            // The default for the validation callback is to reject the URL.
            bool result = false;
            Uri redirectionUri = new Uri(redirectionUrl);
            // Validate the contents of the redirection URL. In this simple validation
            // callback, the redirection URL is considered valid if it is using HTTPS
            // to encrypt the authentication credentials. 
            if (redirectionUri.Scheme == "https")
            {
                result = true;
            }
            return result;
        }

        #region 获取服务器版本

        /// <summary>
        /// 获取服务器版本
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public async static Task<ExchangeVersion> GetServerVersion(ExchangeService service)
        {
            try
            {
                await GetFolderLogin(service);
                var serverInfo = service.ServerInfo;
                if (serverInfo != null)
                {
                    var value = $"{serverInfo.MajorVersion}.{serverInfo.MinorVersion}.{serverInfo.MajorBuildNumber}.{serverInfo.MinorBuildNumber}";
                    var version = (serverInfo.VersionString ?? string.Empty) + ";" + value;
                    //return version;  //V2_8;15.00.0847.031
                    return ConvertToVersionType(version);
                }
                return ExchangeVersion.Exchange2007_SP1;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 转换格式，格式 Exchange2007;8.0.1.000
        /// </summary>
        /// <param name="versionStringAndBuildNum"></param>
        /// <returns></returns>
        public static ExchangeVersion ConvertToVersionType(string versionStringAndBuildNum)
        {
            ExchangeVersion defaultVersion = ExchangeVersion.Exchange2007_SP1;
            if (string.IsNullOrEmpty(versionStringAndBuildNum))
                return defaultVersion;

            var versions = versionStringAndBuildNum.Split(';');
            if (versions.Length == 1)
            {
                //先尝试Version
                if (TryParse(versions[0].Trim(), out defaultVersion))
                {
                    return defaultVersion;
                }
                else
                {
                    return ConvertToVersionType1(versions[0].Trim());
                }
            }

            //if (versions.Length > 1)
            if (TryParse(versions[0].Trim(), out defaultVersion))
            {
                return defaultVersion;
            }
            else
            {
                return ConvertToVersionType1(versions[1].Trim());
            }
        }

        /// <summary>
        /// 字符串转枚举
        /// </summary>
        /// <param name="str"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        private static bool TryParse(string str, out ExchangeVersion version)
        {
            version = ExchangeVersion.Exchange2007_SP1;
            if (string.IsNullOrEmpty(str))
                return false;

            try
            {
                version = (ExchangeVersion)Enum.Parse(typeof(ExchangeVersion), str);
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 转换版本号，格式15.0.112.000
        /// </summary>
        /// <param name="buildNumber"></param>
        /// <returns></returns>
        private static ExchangeVersion ConvertToVersionType1(string buildNumber)
        {
            ExchangeVersion defaultVersion = ExchangeVersion.Exchange2007_SP1;
            if (string.IsNullOrEmpty(buildNumber))
                return defaultVersion;

            var numbers = buildNumber.Split('.');
            if (numbers.Length != 4)
                return defaultVersion;

            int majorNumber = 0;//主版本号
            int minorNumber = 0;//次版本号

            if (!int.TryParse(numbers[0], out majorNumber)
                || !int.TryParse(numbers[1], out minorNumber))
                return defaultVersion;

            //主版本号未知
            if (majorNumber < 8)
                return defaultVersion;

            //2007版本
            if (majorNumber == 8)
            {
                return ExchangeVersion.Exchange2007_SP1;
            }

            //主版本号未知
            if (majorNumber > 8 && majorNumber < 14)
            {
                return defaultVersion;
            }

            //2010版本
            if (majorNumber == 14)
            {
                switch (minorNumber)
                {
                    case 1:
                        return ExchangeVersion.Exchange2010_SP1;

                    case 2:
                        return ExchangeVersion.Exchange2010_SP2;

                    case 0:
                    default:
                        return ExchangeVersion.Exchange2010;
                }
            }

            //2013版本及以上
            if (majorNumber == 15)
            {
                switch (minorNumber)
                {
                    case 0:
                        return ExchangeVersion.Exchange2013_SP1;
                    case 1:
                        return ExchangeVersion.Exchange2016;
                    default:
                        return ExchangeVersion.Exchange2013_SP1;
                }
            }

            //主版本号15以上 版本未知
            //if (majorNumber > 15)
            return ExchangeVersion.Exchange2013_SP1;
        }
        #endregion

        #region 登录相关

        
        /// <summary>
        /// Domain不为空时，用domain登录时获取对应的email地址
        /// </summary>
        /// <param name="service"></param>
        /// <param name="userName"></param>
        /// <returns></returns>
        public async static Task<string> GetEmaiAddressByUrername(ExchangeService service, string userName)
        {
            try
            {
                //该实例在指定的延迟（以毫秒为单位）后将被取消。
                var cts = new CancellationTokenSource(30000);
                var resolutionTypes = await Task.Run(() =>
                 {
                     return service.ResolveName(string.Format("SMTP:{0}", userName));

                 }, cts.Token);

                if (resolutionTypes != null && resolutionTypes.Count > 0)
                {
                    if (resolutionTypes[0].Mailbox.MailboxType == MailboxType.Mailbox)
                    {
                        return resolutionTypes[0].Mailbox.Address;
                    }
                }
                return "";
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 通过拉取root文件夹判断Exchange是否登录成功
        /// </summary>
        /// <param name="service"></param>
        /// <returns></returns>
        public async static Task<bool> GetFolderLogin(ExchangeService service)
        {
            try
            {
                var cts = new CancellationTokenSource(30000);
                var rootfolder = await Task.Run(() =>
                {
                    PropertySet propSet = new PropertySet(BasePropertySet.FirstClassProperties);
                    //邮件文件夹层次结构的根
                    return Folder.Bind(service, WellKnownFolderName.MsgFolderRoot, propSet);
                    //await Item.Bind(service, new ItemId(rootfolder.Id.UniqueId), new PropertySet(BasePropertySet.FirstClassProperties));
                    //rootfolder.ChildFolderCount

                    //var result = service.FindFolders.GetFolderLogin(config, DistinguishedFolderIdNameType.msgfolderroot);
                }, cts.Token);
                if (rootfolder != null && rootfolder.ChildFolderCount > 0)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return false;
        }


        //public bool SimulatedLogin(ExchangeService service, ref string logMsg)
        //{
        //    //请求EWS的配置
        //    //EWSUserConfig config = new EWSUserConfig
        //    //{
        //    //    EMail = accountModel.UserName,
        //    //    Password = accountModel.Priority,
        //    //    EWSURL = string.Format("https://{0}/ews/exchange.asmx", simulatedIp),
        //    //    serverName = accountModel.ReceiveMailServer.ServerName,
        //    //    ExchangeVersion = ExchangeServerVersion.Exchange2007_SP1,
        //    //    IsSimLogin = true
        //    //};
        //    try
        //    {
        //        Folder.Bind(service,)
        //        var inbox = service.FindItems(WellKnownFolderName.Inbox,);
        //        if (inbox != null)
        //        {
        //            return SimulateLoginVerifyMail(config, inbox, accountModel.MailAccount, ref logMsg);
        //        }
        //    }
        //    catch (Exception ex)
        //    {
        //        return false;
        //    }

        //    return false;
        //}


        #endregion
    }
}
